<?php

use libs\Redis;
use think\facade\Log;
use util\QRcode;

//开发者二次开发公共函数统一写入此文件，不要修改function.php以便于系统升级。

/**
 * 根据token获取账号ID
 *
 * @param string $token
 * @param string $model
 * @return mixed
 */
function getIdByToken($token = '', $model = 'user')
{
	if (empty($token)) {
		return 0;
	}
	$id = getModelByValue($model, 'id', "token,$token");
	return $id ?: 0;
}

/**
 * 获取账号token过期时间
 *
 * @param string $token
 * @param string $model
 * @return mixed
 */
function getTokenExpiresTime($token = '', $model = 'user')
{
	$expires_time = getModelByValue($model, 'expires_time', "token,$token");
	return $expires_time ?: 0;
}

/**
 * 将textarea内容转为br换行
 *
 * @param $value
 * @return string|string[]|null
 */
function text2Br($value)
{
	$result = preg_replace('/[\r\n]+/', '<br />', $value);
	return $result;
}

/**
 * 删除全部text标签
 *
 * @param $value
 * @return string|string[]|null
 */
function delTextTag($value)
{
	$result = preg_replace('/[,;\r\n\t\s&ldquo&rdquo&middot&lsquo&rsquo&hellip&mdash&nbsp]+/', '', $value);
	return $result;
}

/**
 * 对象转为数组
 *
 * @param unknown $obj
 * @return mixed
 */
function object2Array($obj)
{
	$_arr = is_object($obj) ? get_object_vars($obj) : $obj;
	foreach ($_arr as $key => $val) {
		$val       = (is_array($val)) || is_object($val) ? object_to_array($val) : $val;
		$arr[$key] = $val;
	}
	return $arr;
}

/**
 * 数组分页函数  核心函数  array_slice
 * 用此函数之前要先将数据库里面的所有数据按一定的顺序查询出来存入数组中
 *
 * @param array $array 查询出来的所有数组
 * @param int   $page  当前第几页
 * @param int   $count 每页多少条数据
 * @return array
 */
function pageArray($array = [], $page = 1, $count = 10)
{
	global $count_page; #定全局变量
	$page       = (empty($page)) ? '1' : $page; #判断当前页面是否为空 如果为空就表示为第一页面
	$start      = ($page - 1) * $count; #计算每次分页的开始位置
	$totals     = count($array);
	$count_page = ceil($totals / $count); #计算总页面数
//    $page_data = array();
	$page_data = array_slice($array, $start, $count);
	return $page_data;  #返回查询数据
}

/**
 * 生成数字验证码
 *
 * @param int $length 长度
 * @return int
 */
function generateCode($length = 6)
{
	$min = pow(10, ($length - 1));
	$max = pow(10, $length) - 1;
	return rand($min, $max);
}

/**
 * 将数组按日期排序, 配合 uasort($data, 'dateSort')使用
 *
 * @param $arr1
 * @param $arr2
 * @return int
 */
function dateSort($arr1, $arr2)
{
	return ($arr1['create_time'] > $arr2['create_time']) ? -1 : 1;
}

/*********************************分享链接或其他使用************************************************/
/** 生成短网址
 *
 * @param String $url 原网址
 * @return String
 */
function getShortUrl($url)
{
	$code = floatval(sprintf('%u', crc32($url)));
	$surl = '';
	while ($code) {
		$mod = fmod($code, 62);
		if ($mod > 9 && $mod <= 35) {
			$mod = chr($mod + 55);
		} elseif ($mod > 35) {
			$mod = chr($mod + 61);
		}
		$surl .= $mod;
		$code = floor($code / 62);
	}
	return $surl;
}

/**
 * 加密
 *
 * @param string $string
 * @param string $skey
 * @return mixed
 */
function encode($string = '', $skey = 'app_key')
{
	$strArr   = str_split(base64_encode($string));
	$strCount = count($strArr);
	foreach (str_split($skey) as $key => $value)
		$key < $strCount && $strArr[$key] .= $value;
	return str_replace(array('=', '+', '/'), array('O0O0O', 'o000o', 'oo00o'), join('', $strArr));
}

/**
 * 解密
 *
 * @param string $string
 * @param string $skey
 * @return bool|string
 */
function decode($string = '', $skey = 'app_key')
{
	$strArr   = str_split(str_replace(array('O0O0O', 'o000o', 'oo00o'), array('=', '+', '/'), $string), 2);
	$strCount = count($strArr);
	foreach (str_split($skey) as $key => $value)
		$key <= $strCount && isset($strArr[$key]) && $strArr[$key][1] === $value && $strArr[$key] = $strArr[$key][0];
	return base64_decode(join('', $strArr));
}

/*********************************分享链接或其他使用************************************************/

/**
 * 生成网址的二维码 返回图片地址
 *
 * @param string $url  扫描二维码的打开链接
 * @param int    $size 二维码大小
 * @param string $path 二维码保存路径
 * @return string
 */
function Qrcode($url = '', $size = 8, $path = 'uploads/qrcode/')
{
	$dir = './' . $path;
	if (!file_exists($dir)) {
		mkdir($dir, 0755, true);
	}

	$fileName = $dir . uniqid() . '.png';
	if (!file_exists($fileName)) {
		$level = 'L';
		$data  = $url;
		QRcode::png($data, $fileName, $level, $size, 2, true);
	}
	return $fileName;
}

/**
 * ### getBaseUrl function
 * // utility function that returns base url for
 * // determining return/cancel urls
 *
 * @return string
 */
function getBaseUrl()
{
	if (PHP_SAPI == 'cli') {
		$trace        = debug_backtrace();
		$relativePath = substr(dirname($trace[0]['file']), strlen(dirname(dirname(__FILE__))));
		echo "Warning: This sample may require a server to handle return URL. Cannot execute in command line. Defaulting URL to http://localhost$relativePath \n";
		return "http://localhost" . $relativePath;
	}
	$protocol = 'http';
	if ($_SERVER['SERVER_PORT'] == 443 || (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on')) {
		$protocol .= 's';
	}
	$host    = $_SERVER['HTTP_HOST'];
	$request = $_SERVER['PHP_SELF'];
	return dirname($protocol . '://' . $host . $request);
}

/**
 * 计算概率
 *
 * @param $proArr
 * @return int|string
 */
function getRand($proArr)
{
	$result = '';
	//概率数组的总概率精度
	$proSum = array_sum($proArr);

	//概率数组循环
	foreach ($proArr as $key => $proCur) {
		$randNum = mt_rand(1, $proSum);
		if ($randNum <= $proCur) {
			$result = $key;
			break;
		} else {
			$proSum -= $proCur;
		}
	}
	unset ($proArr);
	return $result;
}

/**
 * 处理图片
 *
 * @param string $data      数据, 附件表ID
 * @param int    $is_one    是否取单图,1为单图
 * @param string $delimiter 分隔符
 * @return string
 */
function getImage($data = '', $is_one = 0, $delimiter = ',')
{
	$arr = explode($delimiter, $data);
	if ($is_one == 1) {
		return get_file_path($arr[0], 1);
	} else {
		$data = [];
		foreach ($arr as $key => $value) {
			$data[] = get_file_path($value, 1);
		}
		return $data;
	}
}

/**
 * 获取图片的缩略图
 *
 * @param string $data      数据
 * @param int    $is_one    是否取单图,1为单图
 * @param string $delimiter 分隔符
 * @return array|string
 */
function getThumbImage($data = '', $is_one = 0, $delimiter = ',')
{
	$arr = explode($delimiter, $data);
	if ($is_one == 1) {
		return get_file_thumb($arr[0], 1, 1);
	} else {
		$data = [];
		foreach ($arr as $key => $value) {
			$data[] = get_file_path($value, 1, 1);
		}
		return $data;
	}
}

/**
 * 检测是否手机访问
 */
function isMobile()
{
	$mobile = array();
	static $mobilebrowser_list = 'Mobile|iPhone|Android|WAP|NetFront|JAVA|OperasMini|UCWEB|WindowssCE|Symbian|Series|webOS|SonyEricsson|Sony|BlackBerry|Cellphone|dopod|Nokia|samsung|PalmSource|Xphone|Xda|Smartphone|PIEPlus|MEIZU|MIDP|CLDC';
	//note 获取手机浏览器
	if (preg_match("/$mobilebrowser_list/i", $_SERVER['HTTP_USER_AGENT'], $mobile)) {
		return true;
	} else {
		if (preg_match('/(mozilla|chrome|safari|opera|m3gate|winwap|openwave)/i', $_SERVER['HTTP_USER_AGENT'])) {
			return false;
		} else {
			if ($_GET['mobile'] === 'yes') {
				return true;
			} else {
				return false;
			}
		}
	}
}

/**
 * 是否微信浏览器访问
 *
 * @return bool
 * @author nagi
 */
function isWechat()
{
	if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false) {
		return true;
	} else {
		return false;
	}
}

/**
 * 过滤用户恶意攻击
 *
 * @param $input
 * @return mixed|string|string[]|null
 */
function filterContent($input)
{
	$input = strip_tags(trim($input));
	$input = htmlentities($input, ENT_QUOTES, 'UTF-8');
	$input = str_ireplace(array('\\', 'script', 'expression'), array('&#x005C', 'scripｔ', 'expressioｎ'), $input);
	return $input;
}

/**
 * 生成唯一订单
 */
function buildOrderNo()
{
	return date('ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
}

/**
 * 验证手机号格式
 *
 * @param string $mobile 手机号
 * @return bool 验证通过返回true，否则返回false
 */
function validateMobile(string $mobile): bool
{
	// 正则表达式：以1开头，第二位为3-9，后面跟9位数字，总共11位
	$pattern = '/^1[3-9]\d{9}$/';
	return (bool)preg_match($pattern, $mobile);
}

/**
 * excel去空值
 */
function excelToEmpty($arr = [])
{
	if (count($arr) < 1) {
		return false;
	}
	$flag = false;
	foreach ($arr as $key => $val) {
		if (!empty($val)) {
			$flag = true;
		}
	}
	if ($flag) {
		return $arr;
	}
}

/**
 * curl POST 请求
 *
 * @param        $url
 * @param        $requestData
 * @param string $requestMethod
 * @param array  $header
 * @return bool|string
 */
function curlRequest($url, $requestData, $requestMethod = 'POST', $header = ["Content-Type: application/json"])
{
	$ch = curl_init();
	try {
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_POST, $requestMethod);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $requestData);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); //强制协议为1.0 可以解决第一次速度慢
		$res = curl_exec($ch);
		return $res;
	} catch (Exception $e) {
		dd($e->getMessage());
	} finally {
		//关闭URL请求
		curl_close($ch);
	}
}

/*
 * 生成第三方3rd_session
 */
function createUserToken()
{
	$session3rd = '';
	$strPol     = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
	$max        = strlen($strPol) - 1;
	for ($i = 0; $i < 16; $i++) {
		$session3rd .= $strPol[rand(0, $max)];
	}
	return $session3rd;
}

/**
 * 生成唯一字符串
 */
function generateUniqueString(): string
{
	$time = microtime(true);
	$rand = random_int(0, PHP_INT_MAX);
	return md5($time . $rand);
}

/**
 * 获取小程序配置信息
 *
 * @param $name
 * @return mixed
 * @throws Exception
 */
function getMiniConfig($name = 'dy_xcx')
{
	$db_config = AppSetting::field('config')->where('name', $name)->value('config');
	if (empty($db_config)) {
		throw new Exception('抖音小程序配置信息获取失败');
	}
	return json_decode($db_config, true);
}

/*
 * 获取最近7天
 */
function getRecentDays()
{
	$redis      = extension_loaded('redis') ? Redis::getRedis() : null;
	$redis_data = null;
	if ($redis) {
		$redis_data = $redis->get(config('redis_keys')['days']);
		$redis_data = $redis_data ? json_decode($redis_data, true) : [];
	}

	if ($redis_data) {
		$days = $redis_data;
	} else {
		$week = array("日", "一", "二", "三", "四", "五", "六");

		for ($i = 6; $i >= 0; $i--) {
			if ($i > 0) {
				$date = date('Y-m-d', strtotime('-' . $i . ' day', time()));
			} else {
				$date = date('Y-m-d', time());
			}
			$days[] = [
				'text1' => '周' . $week[date('w', strtotime($date))],
				'text2' => time_format(strtotime($date), 4),
				'value' => $date,
			];
		}
		if ($redis) {
			$redis->setex(config('redis_keys')['days'], 60 * 60 * 12, json_encode($days));
		}
	}
	return $days;
}

/*
 * 获取最近15天
 */
function getTwoWeek($day = 15)
{
	$redis      = extension_loaded('redis') ? Redis::getRedis() : null;
	$redis_data = null;
	if ($redis) {
		$redis_data = $redis->get(config('redis_keys')['two_week']);
		$redis_data = $redis_data ? json_decode($redis_data, true) : [];
	}

	if ($redis_data) {
		$days = $redis_data;
	} else {
		$days = [];

		for ($i = 0; $i < $day; $i++) {
			if ($i > 0) {
				$date = date('Y-m-d', strtotime('+' . $i . ' day', time()));
			} else {
				$date = date('Y-m-d', time());
			}
			$value        = time_format(strtotime($date), 2);
			$days[$value] = $value;
		}
		if ($redis) {
			$redis->setex(config('redis_keys')['two_week'], 60 * 60 * 12, json_encode($days));
		}
	}
	return $days;
}

/**
 * 初始化日志路径
 *
 * @param string $path
 * @return void
 */
function initLogPath(string $path)
{
	Log::init([
		'type' => 'file',
		'path' => app()->getRootPath() . "runtime/$path/",
	]);
}

/**
 * 将平面分类数组转换为树形结构
 *
 * @param array $categories 包含分类数据的数组
 * @param int   $parentId   父分类ID，默认为0表示根节点
 * @return array 树形结构的分类数据
 */
function buildCategoryTree(array $categories, int $parentId = 0)
{
	$tree = [];
	// 遍历所有分类，找出属于当前父分类的子分类
	foreach ($categories as $category) {
		if ($category['pid'] === $parentId) {
			// 递归查找当前分类的子分类
			$children = buildCategoryTree($categories, $category['id']);

			// 如果有子分类，则添加到当前分类的children属性中
			if (!empty($children)) {
				$category['children'] = $children;
			}

			// 将当前分类添加到树形结构中
			$tree[] = $category;
		}
	}
	return $tree;
}
